package cn.summit.log;

import cn.summit.log.config.AspectLogProperties;
import cn.summit.log.dto.LogInfoDTO;
import cn.summit.log.service.AccessLogService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.UUID;


@Slf4j
@Aspect
public class AccessLogAspect {

    private final AccessLogService accessLogService;

    private final AspectLogProperties aspectLogProperties;


    public AccessLogAspect(AccessLogService accessLogService,
        AspectLogProperties aspectLogProperties) {
        this.accessLogService = accessLogService;
        this.aspectLogProperties = aspectLogProperties;


    }

    /**
     * 切入点
     */
    @Pointcut(value = "execution(public * cn..*.controller..*Controller.*(..))")
    public void logPointcut() {}

    /**
     * 环绕通知
     *
     * @param joinPoint 信息
     * @return obj
     * @throws Throwable 异常
     */
    @Around("logPointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        LogInfoDTO logInfoDTO = doProceedBefore(joinPoint);
        if (logInfoDTO == null) {
            return joinPoint.proceed();
        }
        accessLogService.doBefore(logInfoDTO);

        String uuid = UUID.randomUUID().toString();

        if (aspectLogProperties.getArgsDetailLog()) {
			System.out.println("===========================================");
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder
                .getRequestAttributes();
            if (attributes == null) {
                log.error("请求request获取失败");
                return joinPoint.proceed();
            }
            HttpServletRequest request = attributes.getRequest();

            log.debug("requestInfo=>标识[{}] IP:{} ARGS:{}", uuid, request.getRemoteAddr(),
                Arrays.toString(joinPoint.getArgs()));

        }
        //执行方法
        Object result = joinPoint.proceed();

        if (aspectLogProperties.getArgsDetailLog()) {
            log.debug("responseInfo=>标识[{}]RESPONSE:{}", uuid, result);
        }

        doProceedAfter(joinPoint, logInfoDTO);
        accessLogService.doAfter(logInfoDTO);

        return result;
    }

    /**
     * 环绕后处理
     *
     * @param joinPoint 信息
     * @param logInfoDTO 访问信息
     */
    private void doProceedAfter(ProceedingJoinPoint joinPoint, LogInfoDTO logInfoDTO) {
        logInfoDTO.setEndTime(LocalDateTime.now());
    }

    /**
     * 环绕前处理
     *
     * @param joinPoint 信息
     * @return 访问信息
     */
    private LogInfoDTO doProceedBefore(ProceedingJoinPoint joinPoint) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder
            .getRequestAttributes();
        if (requestAttributes == null) {
            log.error("获取ServletRequestAttributes failed");
            return null;
        }
        Method method = signature.getMethod();
        Class<?> controllerClass = method.getDeclaringClass();

        LogInfoDTO logInfo = new LogInfoDTO();
        HttpServletRequest request = requestAttributes.getRequest();
        logInfo.setRequest(request);
        logInfo.setHttpMethod(request.getMethod());
        logInfo.setUri(request.getRequestURI());
        logInfo.setClassMethod(controllerClass.getName() + "#" + method.getName());
        //logInfo.setMethodDescription();
        logInfo.setStartTime(LocalDateTime.now());
        //logInfo.setErrorInfo();
        return logInfo;
    }
}
